Description:
This audit detects if there is a loop in a lock graph.
It can happen that two or more threads will lock monitors in such an order, that they will mutually lock each other. In other words, a thread is waiting for some other monitors while it is also an owner of some monitors; consequently, preventing threads that own the monitors it is waiting for to proceed.
This message is produced for each entering monitor statement which corresponds to the edge in a lock graph. Also, for each message, the possible call path from the thread entry point is reported.
By default, only the shortest loop is reported; however, if you specify the report-all-loops message
property as true, then all loops will be reported.
To build a lock graph, the analyzer performs a recursive traverse of the call graph starting
from thread entry points.
By default, only methods passed to the constructor of the System.Threading.ThreadStart
delegate are considered as entry points.
If you specify the all-public-reentrant parameter in the audit's properties,
then all public methods will be considered as entry points.
When the method of some interface is invoked,
the analyzer considers that that method can be called for any class implementing this interface.
By default, the analyzer ignores alien classes (i.e., classes where sources are not available
for analysis). This is done to remove false dependencies in the lock graph caused by the invocation of virtual methods
of the Object class such as
Equals() or
GetHashCode().
To prohibit such restrictions, set the override-alien-methods property to true.
Incorrect:
class Pipe {
private Queue from;
private Queue to;
// Deadlock can happen if one thread invokes sendForward and
// some other thread at the same time invokes sendBackward.
// It is possible that the first thread locks "from" and the second locks "to".
// Then neither of them can continue execution because the monitor that one thread is going
// to lock is already locked by the other thread.
public void SendForward() {
lock (from) {
lock (to) {
to.PutLast(from.GetFirst());
}
}
}
public void SendBackward() {
lock (to) {
lock (from) {
from.PutFirst(to.GetLast());
}
}
}
}
Correct:
class Pipe {
private Queue from;
private Queue to;
public void SendForward() {
lock (from) {
lock (to) {
to.putLast(from.GetFirst());
}
}
}
public void SendBackward() {
lock (from) {
lock (to) {
from.PutFirst(to.getLast());
}
}
}
}